home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / util2 / pgp22src.zip / SRC / CONFIG.C < prev    next >
C/C++ Source or Header  |  1993-03-07  |  14KB  |  557 lines

  1. /*    config.c  - config file parser by Peter Gutmann
  2.     Parses config file for PGP
  3.  
  4.     Modified 24 Jun 92 - HAJK
  5.     Misc fixes for VAX C restrictions.
  6.  
  7. */
  8.  
  9. #include <ctype.h>
  10. #include <string.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include "usuals.h"
  14. #include "fileio.h"
  15. #include "pgp.h"
  16. #include "config.h"
  17. #include "charset.h"
  18.  
  19. static int lookup( char *key, int keyLength, char *keyWords[], int range );
  20. static int extractToken( char *buffer, int *endIndex, int *length );
  21. static int getaString( char *buffer, int *endIndex );
  22. static int getAssignment( char *buffer, int *endIndex, INPUT_TYPE settingType );
  23. static void processAssignment( int intrinsicIndex );
  24.  
  25. /* The external config variables we can set here are referenced in pgp.h */
  26.  
  27. /* Return values */
  28.  
  29. #define ERROR    -1
  30. #define OK        0
  31.  
  32. /* The types of error we check for */
  33.  
  34. enum { NO_ERROR, ILLEGAL_CHAR_ERROR, LINELENGTH_ERROR };
  35.  
  36. #define CPM_EOF            0x1A    /* ^Z = CPM EOF char */
  37.  
  38. #define MAX_ERRORS        3        /* Max.no.errors before we give up */
  39.  
  40. #define LINEBUF_SIZE    100        /* Size of input buffer */
  41.  
  42. static int line;                /* The line on which an error occurred */
  43. static int errCount;            /* Total error count */
  44. static boolean hasError;        /* Whether this line has an error in it */
  45.  
  46. /* The settings parsed out by getAssignment() */
  47.  
  48. static char str[ LINEBUF_SIZE ];
  49. static int value;
  50. static boolean flag;
  51. static char *errtag;    /* prefix for printing error messages */
  52. static char optstr[100];    /* option being processed */
  53.  
  54. /* A .CFG file roughly follows the format used in the world-famous HPACK
  55.    archiver and is as follows:
  56.  
  57.     - Leading spaces/tabs (whitespace) are ignored.
  58.  
  59.     - Lines with a '#' as the first non-whitespace character are treated as
  60.       comment lines.
  61.  
  62.     - All other lines are treated as config options for the program.
  63.  
  64.     - Lines may be terminated by either linefeeds, carriage returns, or
  65.       carriage return/linefeed pairs (the latter being the DOS default method
  66.       of storing text files).
  67.  
  68.     - Config options have the form:
  69.  
  70.       <option> '=' <setting>
  71.  
  72.       where <setting> may be 'on', 'off', a numeric value, or a string
  73.       value.
  74.  
  75.     - If strings have spaces or the '#' character inside them they must be
  76.       surrounded by quote marks '"' */
  77.  
  78. /* Intrinsic variables */
  79.  
  80. #define NO_INTRINSICS        (sizeof(intrinsics) / sizeof(intrinsics[0]))
  81.  
  82. enum
  83. {    ARMOR, COMPRESS, SHOWPASS, KEEPBINARY, LANGUAGE,
  84.     MYNAME, TEXTMODE, TMP, TZFIX, VERBOSE, BAKRING,
  85.     ARMORLINES, COMPLETES_NEEDED, MARGINALS_NEEDED, PAGER,
  86.     CERT_DEPTH, CHARSET, CLEAR, SELF_ENCRYPT,
  87.     INTERACTIVE,
  88.     /* options below this line can only be used as command line
  89.      * "long" options */
  90. #define CONFIG_INTRINSICS    BATCHMODE
  91.     BATCHMODE, FORCE
  92. };
  93.  
  94. static char *intrinsics[] =
  95. {    "ARMOR", "COMPRESS", "SHOWPASS", "KEEPBINARY", "LANGUAGE",
  96.     "MYNAME", "TEXTMODE", "TMP", "TZFIX", "VERBOSE", "BAKRING",
  97.     "ARMORLINES", "COMPLETES_NEEDED", "MARGINALS_NEEDED", "PAGER",
  98.     "CERT_DEPTH", "CHARSET", "CLEARSIG", "ENCRYPTTOSELF", 
  99.     "INTERACTIVE",
  100.     /* command line only */
  101.     "BATCHMODE", "FORCE",
  102. };
  103.  
  104. static INPUT_TYPE intrinsicType[] =
  105. {    BOOL, BOOL, BOOL, BOOL, STRING,
  106.     STRING, BOOL, STRING, NUMERIC, NUMERIC, STRING,
  107.     NUMERIC, NUMERIC, NUMERIC, STRING,
  108.     NUMERIC, STRING, BOOL, BOOL,
  109.     BOOL,
  110.     /* command line only */
  111.     BOOL, BOOL,
  112. };
  113.  
  114. /* Possible settings for variables */
  115.  
  116. #define NO_SETTINGS            2
  117.  
  118. static char *settings[] = { "OFF", "ON" };
  119.  
  120.  
  121. /* Search a list of keywords for a match */
  122.  
  123. static int lookup( char *key, int keyLength, char *keyWords[], int range )
  124. {
  125.     int indx, pos = 0, matches = 0;
  126.  
  127.     strncpy(optstr, key, keyLength);
  128.     optstr[keyLength] = '\0';
  129.     /* Make the search case insensitive */
  130.     for( indx = 0; indx < keyLength; indx++ )
  131.         key[ indx ] = to_upper( key[ indx ] );
  132.  
  133.     for( indx = 0; indx < range; indx++ )
  134.         if( !strncmp( key, keyWords[ indx ], keyLength ) )
  135.         {    if (strlen(keyWords[indx]) == keyLength)
  136.                 return indx;    /* exact match */
  137.             pos = indx;
  138.             ++matches;
  139.         }
  140.     
  141.     switch (matches)
  142.     {    case 0: fprintf(stderr, "%s: unknown keyword: \"%s\"\n", errtag, optstr); break;
  143.         case 1: return pos;
  144.         default: fprintf(stderr, "%s: \"%s\" is ambiguous\n", errtag, optstr);
  145.     }
  146.     return ERROR;
  147. }
  148.  
  149. /* Extract a token from a buffer */
  150. static int extractToken( char *buffer, int *endIndex, int *length )
  151. {
  152.     int indx = 0, tokenStart;
  153.     char ch;
  154.  
  155.     /* Skip whitespace */
  156.     for( ch = buffer[ indx ]; ch && ( ch == ' ' || ch == '\t' ); ch = buffer[ indx ] )
  157.         indx++;
  158.     tokenStart = indx;
  159.  
  160.     /* Find end of setting */
  161.     while( indx < LINEBUF_SIZE && ( ch = buffer[ indx ] ) != '\0' && ch != ' ' && ch != '\t' )
  162.         indx++;
  163.     *endIndex += indx;
  164.     *length = indx - tokenStart;
  165.  
  166.     /* Return start position of token in buffer */
  167.     return( tokenStart );
  168. }
  169.  
  170.  
  171. /* Get a string constant */
  172. static int getaString( char *buffer, int *endIndex )
  173.     {
  174.     boolean noQuote = FALSE;
  175.     int stringIndex = 0, bufIndex = 1;
  176.     char ch = *buffer;
  177.  
  178.     /* Skip whitespace */
  179.     while( ch && ( ch == ' ' || ch == '\t' ) )
  180.         ch = buffer[ bufIndex++ ];
  181.  
  182.     /* Check for non-string */
  183.     if( ch != '\"' )
  184.         {
  185.         *endIndex += bufIndex;
  186.  
  187.         /* Check for special case of null string */
  188.         if( !ch )
  189.             {
  190.             *str = '\0';
  191.             return( OK );
  192.             }
  193.  
  194.         /* Use nasty non-rigorous string format */
  195.         noQuote = TRUE;
  196.         }
  197.  
  198.     /* Get first char of string */
  199.     if( !noQuote )
  200.         ch = buffer[ bufIndex++ ];
  201.  
  202.     /* Get string into string */
  203.     while( ch && ch != '\"' )
  204.         {
  205.         /* Exit on '#' if using non-rigorous format */
  206.         if( noQuote && ch == '#' )
  207.             break;
  208.  
  209.         str[ stringIndex++ ] = ch;
  210.         ch = buffer[ bufIndex++ ];
  211.         }
  212.  
  213.     /* If using the non-rigorous format, stomp trailing spaces */
  214.     if( noQuote )
  215.         while( stringIndex > 0 && str[ stringIndex - 1 ] == ' ' )
  216.             stringIndex--;
  217.  
  218.     str[ stringIndex++ ] = '\0';
  219.     *endIndex += bufIndex;
  220.  
  221.     /* Check for missing string terminator */
  222.     if( ch != '\"' && !noQuote )
  223.         {
  224.         if (line)
  225.             fprintf(stderr, "%s: unterminated string in line %d\n", errtag, line );
  226.         else
  227.             fprintf(stderr, "unterminated string: '\"%s'\n", str );
  228.         hasError = TRUE;
  229.         errCount++;
  230.         return( ERROR );
  231.         }
  232.  
  233.     return( OK );
  234.     }
  235.  
  236. /* Get an assignment to an intrinsic */
  237. static int getAssignment( char *buffer, int *endIndex, INPUT_TYPE settingType )
  238. {
  239.     int settingIndex = 0, length;
  240.  
  241.     buffer += extractToken( buffer, endIndex, &length );
  242.  
  243.     /* Check for an assignment operator */
  244.     if ( *buffer != '=' )
  245.     {
  246.         if (line)
  247.             fprintf(stderr, "%s: expected '=' in line %d\n", errtag, line );
  248.         else
  249.             fprintf(stderr, "%s: expected '=' after \"%s\"\n", errtag, optstr);
  250.         hasError = TRUE;
  251.         errCount++;
  252.         return( ERROR );
  253.     }
  254.     buffer++;        /* Skip '=' */
  255.  
  256.     buffer += extractToken( buffer, endIndex, &length );
  257.  
  258.     switch( settingType )
  259.     {
  260.         case BOOL:
  261.             /* Check for known intrinsic - really more general than just
  262.                checking for TRUE or FALSE */
  263.             if( ( settingIndex = lookup( buffer, length, settings, NO_SETTINGS ) ) == ERROR )
  264.             {
  265.                 hasError = TRUE;
  266.                 errCount++;
  267.                 return( ERROR );
  268.             }
  269.  
  270.             flag = ( settingIndex == 0 ) ? FALSE : TRUE;
  271.             break;
  272.  
  273.         case STRING:
  274.             /* Get a string */
  275.             getaString( buffer, &length );
  276.             break;
  277.  
  278.         case NUMERIC:
  279.             /* Get numeric input.  Error checking is a pain since atoi()
  280.                 has no real equivalent of NAN */
  281.             value = atoi( buffer );
  282.             break;
  283.     }
  284.  
  285.     return( settingIndex );
  286. }
  287.  
  288. /* Process an assignment */
  289.  
  290. static void processAssignment( int intrinsicIndex )
  291.     {
  292.     if( !hasError )
  293.         switch( intrinsicIndex )
  294.             {
  295.             case ARMOR:
  296.                 emit_radix_64 = flag;
  297.                 break;
  298.  
  299.             case COMPRESS:
  300.                 compress_enabled = flag;
  301.                 break;
  302.  
  303.             case SHOWPASS:
  304.                 showpass = flag;
  305.                 break;
  306.  
  307.             case KEEPBINARY:
  308.                 keepctx = flag;
  309.                 break;
  310.  
  311.             case LANGUAGE:
  312.                 strncpy(language, str, 15);
  313.                 break;
  314.  
  315.             case BAKRING:
  316.                 strcpy(floppyring, str);
  317.                 break;
  318.  
  319.             case MYNAME:
  320.                 strcpy(my_name, str);
  321.                 break;
  322.  
  323.             case TEXTMODE:
  324.                 if( flag )
  325.                     literal_mode = MODE_TEXT;
  326.                 break;
  327.  
  328.             case TMP:
  329.                 /* directory pathname to store temp files */
  330.                 settmpdir(str);
  331.                 break;
  332.  
  333.             case TZFIX:
  334.                 /* How many hours to add to time() to get GMT. */
  335.                 /* Compute seconds from hours to shift to GMT: */
  336.                 timeshift = 3600L * (long) value;
  337.                 break;
  338.  
  339.             case VERBOSE:
  340.                 switch (value)
  341.                 {
  342.                     case 0: quietmode = TRUE; verbose = FALSE; break;
  343.                     case 1: quietmode = FALSE; verbose = FALSE; break;
  344.                     case 2: quietmode = FALSE; verbose = TRUE; break;
  345.                     default: quietmode = FALSE; verbose = FALSE;
  346.                 }
  347.                 break;
  348.  
  349.             case ARMORLINES:
  350.                 pem_lines = value;
  351.                 break;
  352.  
  353.             case MARGINALS_NEEDED:
  354.                 marg_min = value;
  355.                 if (marg_min < 1)
  356.                     marg_min = 1;
  357.                 break;
  358.  
  359.             case COMPLETES_NEEDED:
  360.                 compl_min = value;
  361.                 if (compl_min < 1)
  362.                     compl_min = 1;
  363.                 if (compl_min > 4)
  364.                     compl_min = 4;
  365.                 break;
  366.  
  367.             case CERT_DEPTH:
  368.                 max_cert_depth = value;
  369.                 if (max_cert_depth < 0)
  370.                     max_cert_depth = 0;
  371.                 if (max_cert_depth > 8)
  372.                     max_cert_depth = 8;
  373.                 break;
  374.  
  375.             case PAGER:
  376.                 strcpy(pager, str);
  377.                 break;
  378.  
  379.             case CHARSET:
  380.                 strcpy(charset, str);
  381.                 break;
  382.  
  383.             case CLEAR:
  384.                 clear_signatures = flag;
  385.                 break;
  386.                 
  387.             case SELF_ENCRYPT:
  388.                 encrypt_to_self = flag;
  389.                 break;
  390.                 
  391.             case INTERACTIVE:
  392.                 interactive_add = flag;
  393.                 break;
  394.                 
  395.             case BATCHMODE: batchmode = flag; break;
  396.             case FORCE: force_flag = flag; break;
  397.             }
  398.     }
  399.  
  400. /* Process an option on a line by itself.  This expects options which are
  401.    taken from the command-line, and is less finicky about errors than the
  402.    config-file version */
  403.  
  404. int processConfigLine( char *option )
  405.     {
  406.     int indx, intrinsicIndex;
  407.     char ch;
  408.  
  409.     /* Give it a pseudo-linenumber of 0 */
  410.     line = 0;
  411.  
  412.     errtag = "pgp";
  413.     errCount = 0;
  414.     for( indx = 0;
  415.          indx < LINEBUF_SIZE && ( ch = option[ indx ] ) != '\0' &&
  416.                 ch != ' ' && ch != '\t' && ch != '=';
  417.          indx++ );
  418.     if( ( intrinsicIndex = lookup( ( char * ) option, indx, intrinsics, NO_INTRINSICS ) ) == ERROR )
  419.         return -1;
  420.     if (option[indx] == '\0' && intrinsicType[intrinsicIndex] == BOOL)
  421.     {    /* boolean option, no '=' means TRUE */
  422.         flag = TRUE;
  423.         processAssignment(intrinsicIndex);
  424.     }
  425.     else /* Get the value to set to, either as a string, a
  426.             numeric value, or a boolean flag */
  427.         if (getAssignment( ( char * ) option + indx, &indx, intrinsicType[ intrinsicIndex ] ) != ERROR)
  428.             processAssignment( intrinsicIndex );
  429.     return(errCount ? -1 : 0);
  430. }
  431.  
  432. /* Process a config file */
  433. int processConfigFile( char *configFileName )
  434. {
  435.     FILE *configFilePtr;
  436.     int ch = 0, theCh;
  437.     int errType, errPos = 0, lineBufCount, intrinsicIndex;
  438.     int indx;
  439.     char inBuffer[ LINEBUF_SIZE ];
  440.  
  441.     line = 1;
  442.     errCount = 0;
  443.     errtag = "config.txt";
  444.  
  445.     if( ( configFilePtr = fopen( configFileName, FOPRTXT ) ) == NULL )
  446.     {
  447.         fprintf(stderr, "Cannot open configuration file %s\n", configFileName );
  448.         return( OK );    /* treat like empty config file */
  449.     }
  450.  
  451.     /* Process each line in the configFile */
  452.     while( ch != EOF )
  453.     {
  454.         /* Skip whitespace */
  455.         while( ( ( ch = getc( configFilePtr ) ) == ' ' || ch == '\t' ) && ch != EOF )
  456.         ;
  457.  
  458.         /* Get a line into the inBuffer */
  459.         hasError = FALSE;
  460.         lineBufCount = 0;
  461.         errType = NO_ERROR;
  462.         while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != EOF )
  463.         {
  464.             /* Check for an illegal char in the data */
  465.             if( ( ch < ' ' || ch > '~' ) && ch != '\r' && ch != '\n' &&
  466.                 ch != ' ' && ch != '\t' && ch != CPM_EOF && ch != EOF )
  467.             {
  468.                 if( errType == NO_ERROR )
  469.                     /* Save position of first illegal char */
  470.                     errPos = lineBufCount;
  471.                 errType = ILLEGAL_CHAR_ERROR;
  472.             }
  473.  
  474.             /* Make sure the path is of the correct length.  Note that the
  475.                code is ordered so that a LINELENGTH_ERROR takes precedence over
  476.                an ILLEGAL_CHAR_ERROR */
  477.             if( lineBufCount > LINEBUF_SIZE )
  478.                 errType = LINELENGTH_ERROR;
  479.             else
  480.                 inBuffer[ lineBufCount++ ] = ch;
  481.  
  482.             if( ( ch = getc( configFilePtr ) ) == '#' )
  483.             {
  484.                 /* Skip comment section and trailing whitespace */
  485.                 while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != EOF )
  486.                     ch = getc( configFilePtr );
  487.                 break;
  488.             }
  489.         }
  490.  
  491.         /* Skip trailing whitespace and add der terminador */
  492.         while(lineBufCount && (( theCh = inBuffer[ lineBufCount - 1 ] ) == ' ' || theCh == '\t' ))
  493.             lineBufCount--;
  494.  
  495.         inBuffer[ lineBufCount ] = '\0';
  496.  
  497.         /* Process the line unless its a blank or comment line */
  498.         if( lineBufCount && *inBuffer != '#' )
  499.         {
  500.             switch( errType )
  501.             {
  502.                 case LINELENGTH_ERROR:
  503.                     fprintf(stderr, "%s: line '%.30s...' too long\n", errtag, inBuffer );
  504.                     errCount++;
  505.                     break;
  506.  
  507.                 case ILLEGAL_CHAR_ERROR:
  508.                     fprintf(stderr, "> %s\n  ", inBuffer );
  509.                     fprintf(stderr, "%*s^\n", errPos, ""); 
  510.                     fprintf(stderr, "%s: bad character in command on line %d\n", errtag, line );
  511.                     errCount++;
  512.                     break;
  513.  
  514.                 default:
  515.                     for( indx = 0;
  516.                          indx < LINEBUF_SIZE && ( ch = inBuffer[ indx ] ) != '\0'
  517.                                 && ch != ' ' && ch != '\t' && ch != '=';
  518.                          indx++ )
  519.                              ;
  520.                     if( ( intrinsicIndex = lookup( inBuffer, indx, intrinsics, CONFIG_INTRINSICS ) ) == ERROR )
  521.                     {
  522.                         errCount++;
  523.                     }
  524.                     else
  525.                     {
  526.                         /* Get the value to set to, either as a string, a
  527.                            numeric value, or a boolean flag */
  528.                         getAssignment( inBuffer + indx, &indx, intrinsicType[ intrinsicIndex ] );
  529.                         processAssignment( intrinsicIndex );
  530.                     }
  531.             }
  532.         }
  533.  
  534.         /* Handle special-case of ^Z if configFile came off an MSDOS system */
  535.         if( ch == CPM_EOF )
  536.             ch = EOF;
  537.  
  538.         /* Exit if there are too many errors */
  539.         if( errCount >= MAX_ERRORS )
  540.             break;
  541.  
  542.         line++;
  543.     }
  544.  
  545.     fclose( configFilePtr );
  546.  
  547.     /* Exit if there were errors */
  548.     if( errCount )
  549.     {
  550.         fprintf(stderr, "%s: %s%d error(s) detected\n\n", configFileName, ( errCount >= MAX_ERRORS ) ?
  551.                 "Maximum level of " : "", errCount );
  552.         return( ERROR );
  553.     }
  554.  
  555.     return( OK );
  556. }
  557.